# -*- coding:utf-8 -*-
from typing import Literal, NoReturn


from DrissionPage.errors import AlertExistsError
from DrissionPage.items import ChromiumElement

from src._typing import MatchLocation

__all__ = ('LocationClicker', )


class LocationClicker(object):

    def __init__(self, ele):
        """
        点击元素，默认左键点击
        Args:
            ele(ChromiumElement): 元素
        """
        self._location: MatchLocation | None = None
        self._ele = ele

    def __call__(self, *args, **kwargs):
        """
        点击元素，默认左键点击
        Args:
            *args:
            **kwargs:

        Returns:

        """
        return self.left(*args, **kwargs)

    @property
    def location(self) -> MatchLocation | None:
        return self._location

    @location.setter
    def location(self, loc_: MatchLocation):
        len_t = len(loc_)
        if len_t != 2:
            raise ValueError(f'位置参数长度必须为2，当前为：{len_t} !')
        self._location = loc_

    def left(self, location: MatchLocation) -> NoReturn:
        """
        根据位置信息, 左键单击元素
        Args:
            location(MatchLocation): 位置信息

        Returns:
            NoReturn

        """
        self.location = location
        cli_x = self._location[0]
        cli_y = self._location[1]
        self._click(client_x=cli_x, client_y=cli_y, button='left')
        # rect = None
        # if timeout == 0:
        #     try:
        #         self._ele.scroll.to_see()
        #         if self._ele.states.is_enabled and self._ele.states.is_displayed:
        #             rect = self._ele.rect.viewport_corners
        #             can_click = True
        #     except NoRectError:
        #         if by_js is False:
        #             raise
        #
        # else:
        #     rect = self._ele.states.has_rect
        #     end_time = perf_counter() + timeout
        #     while not rect and perf_counter() < end_time:
        #         rect = self._ele.states.has_rect
        #         sleep(.001)
        #
        #     if wait_stop and rect:
        #         self._ele.wait.stop_moving(timeout=end_time - perf_counter())
        #     if rect:
        #         self._ele.scroll.to_see()
        #         rect = self._ele.rect.corners
        #         while perf_counter() < end_time:
        #             if self._ele.states.is_enabled and self._ele.states.is_displayed:
        #                 can_click = True
        #                 break
        #             sleep(.001)
        #
        #     elif by_js is False:
        #         raise NoRectError
        #
        # if can_click and not self._ele.states.is_in_viewport:
        #     by_js = True
        #
        # elif can_click and (by_js is False or not self._ele.states.is_covered):
        #     x = rect[1][0] - (rect[1][0] - rect[0][0]) / 2
        #     y = rect[0][0] + 3
        #     try:
        #         r = self._ele.owner.run_cdp('DOM.getNodeForLocation', x=int(x), y=int(y),
        #                                     includeUserAgentShadowDOM=True, ignorePointerEventsNone=True)
        #         if r['backendNodeId'] != self._ele._backend_id:
        #             vx, vy = self._ele.rect.viewport_midpoint
        #         else:
        #             vx, vy = self._ele.rect.viewport_click_point
        #
        #     except CDPError:
        #         vx, vy = self._ele.rect.viewport_midpoint
        #
        #     self._click(vx, vy)
        #     return True

    def right(self, location: MatchLocation):
        """
        根据位置信息, 右键单击元素
        Args:
            location(MatchLocation): 位置信息

        Returns:
            NoReturn

        """
        self.location = location
        cli_x = self._location[0]
        cli_y = self._location[1]
        self._click(client_x=cli_x, client_y=cli_y, button='right')

    def middle(self, location: MatchLocation):
        """
        根据位置信息, 中键单击元素
        Args:
            location(MatchLocation): 位置信息

        Returns:
            NoReturn

        """
        # , get_tab: bool = True
        self.location = location
        cli_x = self._location[0]
        cli_y = self._location[1]
        self._click(client_x=cli_x, client_y=cli_y, button='middle')
        # if get_tab:
        #     tid = self._ele.page.wait.new_tab()
        #     if not tid:
        #         raise RuntimeError('没有出现新标签页。')
        #     return self._ele.page.get_tab(tid)

    def at(self, location: MatchLocation,
           offset_x: int | float | None = None,
           offset_y: int | float | None = None,
           button: str = 'left', count: int = 1) -> NoReturn:
        """
        根据位置信息, 偏移点击元素
        Args:
            location(MatchLocation): 位置信息
            offset_x(int|float|None): 横向偏移量，即宽度上偏移
            offset_y(int|float|None): 纵向偏移量，即高度上偏移
            button(str): 鼠标按键,'left', 'right', 'middle', 'back', 'forward', 默认为 'left':
            count(int): 鼠标点击次数

        Returns:
            NoReturn

        """
        self.location = location
        if offset_x is None:
            offset_x = 0
        if offset_y is None:
            offset_y = 0
        cli_x = self._location[0] + offset_x
        cli_y = self._location[1] + offset_y
        self._click(cli_x, cli_y, button, count)

    def multi(self, location: MatchLocation, times: int = 2, button: str = 'left') -> NoReturn:
        """
        根据位置信息, 多次点击元素
        Args:
            location(MatchLocation): 位置信息
            times(int): 点击次数
            button(str): 鼠标按键,'left', 'right', 'middle', 'back', 'forward', 默认为 'left'

        Returns:
            NoReturn

        """
        # 调用偏移方法，但默认不偏移
        self.at(location=location, count=times, button=button)

    def _click(self, client_x: int | float, client_y: int | float,
               button: Literal['left', 'right', 'middle', 'back', 'forward'] | str = 'left',
               count: int = 1) -> NoReturn:
        """
        实施点击
        Args:
            client_x(int|float): 视口中的x坐标
            client_y(int|float): 视口中的y坐标
            button(str): 鼠标按键,'left', 'right', 'middle', 'back', 'forward'
            count(int): 鼠标点击次数

        Returns:
            NoReturn

        """
        self._ele.owner.run_cdp('Input.dispatchMouseEvent', type='mousePressed', x=client_x,
                                y=client_y, button=button, clickCount=count, _ignore=AlertExistsError)
        self._ele.owner.run_cdp('Input.dispatchMouseEvent', type='mouseReleased', x=client_x,
                                y=client_y, button=button, _ignore=AlertExistsError)


if __name__ == '__main__':
    print('Hello world!')
